﻿using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using NHibernate.Mapping.ByCode;

namespace YJKRevitBase.SqlUtility.ORMSuit
{
	internal static class EntityAutoMappingUtility
	{
		internal static void EntityMappingMethod<X>(IClassMapper<X> inputValue) where X : BaseEntity
		{
			inputValue.Cache(delegate(ICacheMapper k)
			{
				k.Usage(CacheUsage.ReadWrite);
			});
			inputValue.Lazy(false);
			inputValue.Id<int>((X k) => k.Id, delegate(IIdMapper map)
			{
				map.Generator(Generators.Identity);
			});
			Type typeFromHandle = typeof(X);
			Type typeFromHandle2 = typeof(EntityAutoMappingUtility);
			MethodInfo method = typeFromHandle2.GetMethod("Property", BindingFlags.Static | BindingFlags.NonPublic);
			MethodInfo method2 = typeFromHandle2.GetMethod("Bag", BindingFlags.Static | BindingFlags.NonPublic);
			MethodInfo method3 = typeFromHandle2.GetMethod("ManyToOne", BindingFlags.Static | BindingFlags.NonPublic);
			MethodInfo method4 = typeFromHandle2.GetMethod("BagManyToMany", BindingFlags.Static | BindingFlags.NonPublic);
			foreach (PropertyInfo propertyInfo in typeFromHandle.GetProperties())
			{
				if (!propertyInfo.Name.Equals("Id") && propertyInfo.CanRead && propertyInfo.CanWrite && propertyInfo.GetMethod.IsVirtual && propertyInfo.SetMethod.IsVirtual)
				{
					PropertyAttribute propertyAttribute = propertyInfo.GetCustomAttribute(typeof(PropertyAttribute)) as PropertyAttribute;
					ParameterExpression parameterExpression2 = Expression.Parameter(typeFromHandle);
					Expression body = Expression.Property(parameterExpression2, propertyInfo);
					MethodInfo methodInfo;
					if (propertyInfo.PropertyType.IsGenericCollection() && propertyInfo.PropertyType.IsInterface && propertyInfo.PropertyType.DetermineCollectionElementType().IsSubclassOf(EntityAutoMappingUtility.m_baseEntityType))
					{
						if (!(propertyInfo.PropertyType.GetGenericTypeDefinition() == EntityAutoMappingUtility.m_baseIEnumerable))
						{
							goto IL_2F8;
						}
						if (propertyAttribute != null && propertyAttribute.IfIsManyToMany)
						{
							methodInfo = method4.MakeGenericMethod(new Type[]
							{
								typeFromHandle,
								propertyInfo.PropertyType.DetermineCollectionElementType()
							});
							methodInfo.Invoke(null, new object[]
							{
								inputValue,
								Expression.Lambda(body, new ParameterExpression[]
								{
									parameterExpression2
								}),
								!propertyAttribute.IfIsManyToManyControl
							});
							goto IL_2F8;
						}
						methodInfo = method2.MakeGenericMethod(new Type[]
						{
							typeFromHandle,
							propertyInfo.PropertyType.DetermineCollectionElementType()
						});
					}
					else if (propertyInfo.PropertyType.IsSubclassOf(EntityAutoMappingUtility.m_baseEntityType))
					{
						methodInfo = method3.MakeGenericMethod(new Type[]
						{
							typeFromHandle,
							propertyInfo.PropertyType
						});
					}
					else
					{
						if (propertyInfo.PropertyType.IsGenericCollection() && propertyInfo.PropertyType.IsInterface)
						{
							goto IL_2F8;
						}
						methodInfo = method.MakeGenericMethod(new Type[]
						{
							typeFromHandle,
							propertyInfo.PropertyType
						});
					}
					methodInfo.Invoke(null, new object[]
					{
						inputValue,
						Expression.Lambda(body, new ParameterExpression[]
						{
							parameterExpression2
						})
					});
				}
				IL_2F8:;
			}
		}

		internal static Action<IClassMapper<X>> EntityMapping<X>() where X : BaseEntity
		{
			return new Action<IClassMapper<X>>(EntityAutoMappingUtility.EntityMappingMethod<X>);
		}

		private static void Property<X, T>(IClassMapper<X> inputValue, Expression<Func<X, T>> inputProperty) where X : BaseEntity
		{
			inputValue.Property<T>(inputProperty);
		}

		private static void Bag<X, T>(IClassMapper<X> inputValue, Expression<Func<X, IEnumerable<T>>> inputBag) where X : BaseEntity
		{
			inputValue.Bag<T>(inputBag, delegate(IBagPropertiesMapper<X, T> bag)
			{
				bag.Cascade(Cascade.All);
				bag.Inverse(true);
				bag.Cache(delegate(ICacheMapper k)
				{
					k.Usage(CacheUsage.ReadWrite);
				});
			});
		}

		private static void BagManyToMany<X, T>(IClassMapper<X> inputValue, Expression<Func<X, IEnumerable<T>>> inputBag, bool ifInVerse) where X : BaseEntity
		{
			Type useThisType = typeof(X);
			Type useAnotherType = typeof(T);
			bool useifInVerse = ifInVerse;
			if (useThisType.GetHashCode() < useAnotherType.GetHashCode())
			{
				useifInVerse = false;
			}
			else if (useThisType.GetHashCode() > useAnotherType.GetHashCode())
			{
				useifInVerse = true;
			}
            //Action<IKeyMapper<X>> <>9__2;
            //Action<IManyToManyMapper> <>9__4;
            //inputValue.Bag<T>(inputBag, delegate(IBagPropertiesMapper<X, T> bag)
            //{
            //    Action<IKeyMapper<X>> keyMapping;
            //    if ((keyMapping = <>9__2) == null)
            //    {
            //        keyMapping = (<>9__2 = delegate(IKeyMapper<X> c)
            //        {
            //            c.Column(useThisType.Name);
            //        });
            //    }
            //    bag.Key(keyMapping);
            //    bag.Cascade(Cascade.All);
            //    bag.Inverse(useifInVerse);
            //    bag.Cache(delegate(ICacheMapper k)
            //    {
            //        k.Usage(CacheUsage.ReadWrite);
            //    });
            //}, delegate(ICollectionElementRelation<T> mapper)
            //{
            //    Action<IManyToManyMapper> mapping;
            //    if ((mapping = <>9__4) == null)
            //    {
            //        mapping = (<>9__4 = delegate(IManyToManyMapper c)
            //        {
            //            c.Column(useAnotherType.Name);
            //        });
            //    }
            //    mapper.ManyToMany(mapping);
            //});
		}

		private static void ManyToOne<X, T>(IClassMapper<X> inputValue, Expression<Func<X, T>> inputProperty) where X : BaseEntity where T : BaseEntity
		{
			inputValue.ManyToOne<T>(inputProperty);
		}

		private const string m_strUseIdName = "Id";

		private const string m_strUsePropertyMethodName = "Property";

		private const string m_strUseBagMethodName = "Bag";

		private const string m_strUseManyToOneMethodName = "ManyToOne";

		private const string m_strUseBagManyMethodName = "BagManyToMany";

		private static Type m_baseEntityType = typeof(BaseEntity);

		private static Type m_baseIEnumerable = typeof(IEnumerable<>);
	}
}
